package com.sghd.candy.module.skill.service;

import com.sghd.candy.module.bag.manager.PlayerBag;
import com.sghd.candy.module.bag.manager.PlayerBagManager;
import com.sghd.candy.module.fight.manager.LevelConfig;
import com.sghd.candy.module.fight.manager.LevelConfigManager;
import com.sghd.candy.module.fight.manager.LevelId;
import com.sghd.candy.module.player.manager.Player;
import com.sghd.candy.module.skill.manager.*;
import com.sghd.common.ramcache.aop.AutoLocked;
import com.sghd.common.ramcache.aop.IsLocked;
import com.sghd.common.utils.math.RandomUtils;
import com.sghd.pojo.StaticConfig;
import com.sghd.pojo.candy.bag.enums.PropType;
import com.sghd.pojo.candy.player.vo.ReqPlayerVo;
import com.sghd.pojo.candy.skill.vo.SkillLevelVo;
import com.sghd.pojo.candy.skill.vo.SkillVo;
import com.sghd.pojo.fight.game.Result;
import com.sghd.pojo.fight.game.RoomType;
import com.sghd.pojo.fight.game.RsetSkillVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

import static com.sghd.pojo.StaticConfig.FIGHT_SKILL_COUNT_PVE;
import static com.sghd.pojo.StaticConfig.FIGHT_SKILL_COUNT_PVP;

/**
 * @author Allen
 * @date 2018/12/07
 */
@Service
public class PlayerSkillService {
    private static final Logger logger = LoggerFactory.getLogger(PlayerSkillService.class);

    @Autowired
    private PlayerSkillManager playerSkillManager;
    @Autowired
    private SkillConfigManager skillConfigManager;
    @Autowired
    private PlayerBagManager playerBagManager;
    @Autowired
    private LevelConfigManager levelConfigManager;

    public Set<Integer> getPlayerSkill(Player player) {
        PlayerSkill playerSkill = playerSkillManager.getPlayerSkill(player.getPlayerId());
        return playerSkill.getSkillLevel().keySet();
    }

    public Map<Integer, Integer> getFightSkill(long playerId, ReqPlayerVo req) {
        // 获取玩家技能背包
        PlayerSkill playerSkill = playerSkillManager.getPlayerSkill(playerId);

        int MAX = FIGHT_SKILL_COUNT_PVP;
        Map<Integer, Integer> skillMap = new HashMap<>(MAX);

        if (req.getType() == RoomType.PVE) {
            MAX = FIGHT_SKILL_COUNT_PVE;
            // 获取关卡必须携带的技能
            LevelConfig levelConfig = levelConfigManager.getLevelConfig(LevelId.valueOf(req.getLevelVo().getBigLevelId(), req.getLevelVo().getLevelId()));
            List<Integer> randomList = new ArrayList<>(levelConfig.getPlayerSkills());
            Collections.shuffle(randomList);
            for (int i = 0; i < (levelConfig.getPlayerSkills().size() > MAX ? MAX : levelConfig.getPlayerSkills().size()); i++) {
                int skillId = randomList.get(i);
                skillMap.put(skillId, playerSkill.getSkillLevel().getOrDefault(skillId, 0));
            }
            // 技能不足时，向上阵技能获取
            if (skillMap.size() < MAX && playerSkill.getFightSkill().size() > 0) {
                randomList = new ArrayList<>(playerSkill.getFightSkill());
                Collections.shuffle(randomList);
                for (int i = 0; i < randomList.size(); i++) {
                    int skillId = randomList.get(i);
                    if (skillMap.containsKey(skillId) || isOnlyPvpSkill(skillId)) {
                        continue;
                    }

                    skillMap.put(skillId, playerSkill.getSkillLevel().getOrDefault(skillId,0));

                    if (skillMap.size() >= MAX) {
                        break;
                    }
                }
            }
        } else {
            // 获取玩家上阵技能
            playerSkill.getFightSkill().forEach(skillId -> {
                skillMap.put(skillId, playerSkill.getSkillLevel().getOrDefault(skillId,0));
            });
        }

        int leftCount = MAX - skillMap.size();

        Set<SkillConfig> set = skillConfigManager.all();

        for (; leftCount > 0; leftCount--) {
            int skillId = -1;
            do {
                int rn = RandomUtils.nextInt(set.size());
                int pos = 0;
                for (SkillConfig skillConfig : set) {
                    if (pos == rn) {
                        skillId = skillConfig.getSkillId();
                        break;
                    } else {
                        pos++;
                    }
                }
            } while ( skillId == -1 ||
                    skillMap.containsKey(skillId) ||
                    isHaveSameEffect(skillId, skillMap.keySet()) ||
                    (req.getType() == RoomType.PVE && isOnlyPvpSkill(skillId)));

            skillMap.put(skillId, playerSkill.getSkillLevel().getOrDefault(skillId, 0));
        }

        return skillMap;
    }

    @AutoLocked
    public Result<String> selectFightSkill(@IsLocked Player player, int skillId) {
        PlayerSkill playerSkill = playerSkillManager.getPlayerSkill(player.getPlayerId());
        if (playerSkill.getSkillLevel().containsKey(skillId)) {

            if (isHaveSameEffect(skillId, playerSkill.getFightSkill())) {
                return Result.valueOf(-1, "已装备相似技能！");
            }

            if (playerSkill.getFightSkill().contains(skillId)) {
                return Result.valueOf(-1, "该技能已装备！");
            }

            playerSkillManager.addFightSkill(playerSkill, skillId);
            return Result.SUCCESS();
        } else {
            return Result.valueOf(-1, "该技能未获得！");
        }
    }

    @AutoLocked
    public Result<String> removeFightSkill(@IsLocked Player player, int skillId) {
        PlayerSkill playerSkill = playerSkillManager.getPlayerSkill(player.getPlayerId());
        if (playerSkill.getFightSkill().contains(skillId)) {
            playerSkillManager.removeFightSkill(playerSkill, skillId);
            return Result.SUCCESS();
        } else {
            return Result.valueOf(-1, "该技能未装备！");
        }
    }

    public Result<String> selectFightSkill(long playerId, Set<Integer> fightSkill) {
        PlayerSkill playerSkill = playerSkillManager.getPlayerSkill(playerId);
        StringBuffer errorIds = new StringBuffer();
        for (Integer skillId : fightSkill) {
            if (!playerSkill.getSkillLevel().containsKey(skillId)) {
                if (errorIds.length() == 0) {
                    errorIds.append(skillId);
                } else {
                    errorIds.append(",").append(skillId);
                }
            }
        }

        if (errorIds.length() == 0) {
            playerSkillManager.setFightSkill(playerSkill, fightSkill);
            return Result.SUCCESS();
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("玩家ID[{}]，选择战斗技能出错，技能[{}]不存在！", playerId, errorIds);
            }
            return Result.valueOf(-1, "选择战斗技能出错，技能" + errorIds + "不存在");
        }
    }

    public void addSkill(Player player, int skillId) {
        PlayerSkill playerSkill = playerSkillManager.getPlayerSkill(player.getPlayerId());
        playerSkillManager.addPlayerSkill(playerSkill, skillId);
    }

    public Result<String> upgrade(long playerId, int skillId) {
        PlayerSkill playerSkill = playerSkillManager.getPlayerSkill(playerId);
        int skillLevel = playerSkill.getSkillLevel().get(skillId);
        if (skillLevel < 3) {
            SkillConfig skillConfig = skillConfigManager.getSkillConfig(skillId);
            if (skillConfig == null) {
                if (logger.isDebugEnabled()) {
                    logger.debug("玩家ID[{}]，升级技能出错，在技能库里未找到该技能[{}]！", playerId, skillId);
                }
                return Result.valueOf(-1, "在技能库里未找到该技能！");
            } else {
                UpgradeSkill upgradeSkill = skillConfig.getUpgradeConfig().get(skillLevel + 1);
                if (playerSkill.getDebris() < upgradeSkill.getDebris()) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("玩家ID[{}]，升级技能出错，技能碎片不够！", playerId);
                    }
                    return Result.valueOf(-1, "技能碎片不够！");
                }
                PlayerBag playerBag = playerBagManager.getPlayerBag(playerId);
                if (playerBag.getMoney() < upgradeSkill.getMoney()) {
                    if (logger.isDebugEnabled()) {
                        logger.debug("玩家ID[{}]，升级技能出错，背包金币不够！", playerId);
                    }
                    return Result.valueOf(-1, "背包金币不够！");
                }
                playerBagManager.change(playerBag, PropType.MONEY,-1 * upgradeSkill.getMoney());
                playerSkillManager.upgradeSkill(playerSkill, skillId, upgradeSkill.getDebris());
                return Result.valueOf(playerSkill.getDebris().toString());
            }
        } else {
            if (logger.isDebugEnabled()) {
                logger.debug("玩家ID[{}]，升级技能出错，技能[{}]已最高级！", playerId, skillId);
            }
            return Result.valueOf(-1, "该技能已最高级");
        }
    }

    public void change(Player player, int changeNum) {
        PlayerSkill playerSkill = playerSkillManager.getPlayerSkill(player.getPlayerId());
        playerSkillManager.change(playerSkill, changeNum);
    }

    public RsetSkillVo random(Player player, RsetSkillVo resetVo) {
        long money = 0;
        if (resetVo.getRandomCount() > StaticConfig.SKILL_RANDOM_FREE_COUNT || resetVo.getLockCount() > 0) {
            if (resetVo.getRandomCount() > StaticConfig.SKILL_RANDOM_FREE_COUNT) {
                money = (long) Math.pow(2, resetVo.getRandomCount() - StaticConfig.SKILL_RANDOM_FREE_COUNT - 1) * 1000;
            }
            if (resetVo.getLockCount() > 0) {
                money += Math.pow(2, resetVo.getLockCount() - 1) * 1000;
            }

            PlayerBag playerBag = playerBagManager.getPlayerBag(player.getPlayerId());

            if (playerBag.getMoney() < money) {
                if (logger.isDebugEnabled()) {
                    logger.debug("玩家ID[{}]，背包金币不足，无法更换技能！", player.getPlayerId());
                }
                return resetVo.setResult(Result.valueOf(-1, "背包金币不足，无法更换！"));
            }

            playerBagManager.change(playerBag, PropType.MONEY, -1 * money);
        }
        return resetVo.setResult(Result.valueOf(0, money));
    }

    public SkillVo skillList(Player player) {

        PlayerSkill playerSkill = playerSkillManager.getPlayerSkill(player.getPlayerId());
        SkillVo skillVo = SkillVo.vauleOf(playerSkill.getDebris());
        playerSkill.getSkillLevel().forEach((skillId, level) -> {
            SkillLevelVo skillLevelVo = new SkillLevelVo();
            skillLevelVo.setLevel(level);
            if (playerSkill.getFightSkill().contains(skillId)) {
                skillLevelVo.setFight(true);
            }
            skillVo.getSkills().put(skillId, skillLevelVo);
        });

        return skillVo;
    }

    private static final int[] recovers = {1002, 10013, 10014, 10023};
    private static final int[] magicShields = {1001, 1006, 1007, 1008, 1009};
    private static final int[] magicExchanges = {10011, 10016, 10017, 10018};

    private boolean isHaveSameEffect(int skillId, Set<Integer> fightSkill) {
        int[] sameEffects = null;

        for (int _skillId : recovers) {
            if (skillId == _skillId) {
                sameEffects = recovers;
            }
        }

        for (int _skillId : magicShields) {
            if (skillId == _skillId) {
                sameEffects = magicShields;
            }
        }

        for (int _skillId : magicExchanges) {
            if (skillId == _skillId) {
                sameEffects = magicExchanges;
            }
        }

        if (sameEffects != null) {
            for (int _skillId : sameEffects) {
                if (fightSkill.contains(_skillId)) {
                    return true;
                }
            }
        }

        return false;
    }

    private static final int[] pvpSkills = {10014,10015,10021,10024,10026,10032,10034,10037};
    private boolean isOnlyPvpSkill(int skillId) {
        for (int _skillId : pvpSkills) {
            if (_skillId == skillId) {
                return true;
            }
        }
        return false;
    }
}
